/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../data_struct/head.h"
#include "../helper_objs/head.h"
#include "../config/head.h"
#include "../impl/head.h"
#include "../macro/head.h"
#include "../msg/head.h"
#include "connection.h"

namespace xos_http
{

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static connection::ITEM_DATA xos_item_data;

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    connection::connection()
    {
        init_data();
    }

    connection::~connection()
    {}

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int connection::get_xos_item_data( ITEM_DATA*& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    const char * connection::get_local_ip( const char** lppszIp, char* lpszIp, int nSize ) const
    {
        if( lppszIp )
        {
            *lppszIp = m_local_ip.c_str();
        }
        if( lpszIp )
        {
            mgr::container()->crt()->strcpy( lpszIp, nSize, m_local_ip.c_str() );
        }
        return m_local_ip.c_str();
    }

    int connection::get_local_port( int * pPort ) const
    {
        if( pPort )
        {
            *pPort = m_nLocalPort;
        }
        return m_nLocalPort;
    }

    int connection::set_local_addr( const char* lpszIp, int nPort )
    {
        int ret = 0;
        if( lpszIp )
        {
            m_local_ip = lpszIp;
        }
        m_nLocalPort = nPort;
        prop()->set( "local_ip", m_local_ip.c_str() );
        prop()->set( "local_port", m_nLocalPort );
        return ret;
    }

    const char * connection::get_peer_ip( const char ** lppszIp, char * lpszIp, int nSize ) const
    {
        if( lppszIp )
        {
            *lppszIp = m_peer_ip.c_str();
        }
        if( lpszIp )
        {
            mgr::container()->crt()->strcpy( lpszIp, nSize, m_peer_ip.c_str() );
        }
        return m_peer_ip.c_str();
    }

    int connection::get_peer_port( int * pPort ) const
    {
        if( pPort )
        {
            *pPort = m_nPeerPort;
        }
        return m_nPeerPort;
    }

    int connection::set_peer_addr( const char* lpszIp, int nPort )
    {
        int ret = 0;
        if( lpszIp )
        {
            m_peer_ip = lpszIp;
        }
        m_nPeerPort = nPort;
        prop()->set( "peer_ip", m_peer_ip.c_str() );
        prop()->set( "peer_port", m_nPeerPort );
        return ret;
    }

    int connection::set_net_connect( net::i_connect* pConnect )
    {
        int ret = 0;
        m_pNetConnect = pConnect;
        return ret;
    }

    net::i_connect* connection::get_net_connect() const
    {
        return m_pNetConnect;
    }

    xos_net::i_connect * connection::xos_connect()
    {
        return this;
    }

    http::i_connect * connection::http_connect()
    {
        return this;
    }

    int connection::encode( xos_box::i_list * pList )
    {
        int ret = 0;

        if( !m_pSsl )
        {
            return 0;
        }

        m_pSsl->encode( pList, m_pSendNetEncodeDataList );
        m_pSendNetEncodeDataList->swap( pList );

        return ret;
    }

    int connection::decode( xos_box::i_buf *& pBuf )
    {
        int ret = 0;

        if( !m_pSsl )
        {
            m_pRecvDataList->push_back( pBuf );
            pBuf = 0;
            return 0;
        }

        m_pRecvNetEncodeDataList->push_back( pBuf );
        pBuf = 0;

        // decode返回值：
        // 
        //  0 : 解析数据成功
        //  1 : 连接成功
        //  2 : 连接断开
        // -1 : 连接失败，协议或数据错误。服务端接受连接时才会发生，此时会保留全部数据，以便可以利用它来切换到非ssl的明文协议状态
        // -2 : 连接需要更多数据
        // -3 : 解析失败，协议或数据错误
        // -4 : 解析需要更多数据
        // -5 : 写入BIO失败，不太可能
        ret = m_pSsl->decode( m_pRecvNetEncodeDataList, m_pRecvDataList, m_pSendNetEncodeDataList );

        if( -1 == ret )
        {
            m_pRecvDataList->add_to_tail( m_pRecvNetEncodeDataList );
            m_pRecvNetEncodeDataList->release_all();
            m_pSendNetEncodeDataList->release_all();
            xos_stl::release_interface( m_pSsl );
        }

        if( ( -3 == ret ) || ( -5 == ret ) )
        {
            ret = 1;
        }
        else
        {
            ret = 0;
        }

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // xos_net::i_connect
    // 

    xos_net::i_connect * connection::create_accept_connect()
    {
        connection::T * pConnect = 0;
        xos_stl::init_pool_item( pConnect );
        pConnect->m_pListenConnect = this;
        pConnect->m_pPort = m_pPort;
        pConnect->m_pSsl = m_pPort->m_pSslMgr->ssl();
        pConnect->m_pSsl->init_ssl();
        return pConnect;
    }

    xos_box::i_notify * connection::connect_notify()
    {
        return m_pNetNotify;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // xos_http::i_connect
    // 

    xos_box::i_notify * connection::fast_notify()
    {
        return m_pFastNotify;
    }

    xos_box::i_notify * connection::slow_notify()
    {
        return m_pSlowNotify;
    }

    xos_box::i_list * connection::recv_list()
    {
        return m_pRecvDataList;
    }

    xos_box::i_str_property * connection::prop()
    {
        return m_pProperty;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int connection::init_data()
    {
        int ret = 0;

        // http
        m_bHttpFailed = false;
        m_pProcTask = 0;
        m_pRecvTask = 0;

        // 收发缓冲区
        m_pSendNetEncodeDataList = 0;
        m_pRecvNetEncodeDataList = 0;
        m_pRecvDataList = 0;

        // net
        m_pNetConnect = 0;
        m_local_ip = "";
        m_nLocalPort = 0;
        m_peer_ip = "";
        m_nPeerPort = 0;

        // port
        m_pListenConnect = 0;
        m_pPort = 0;
        m_pSsl = 0;

        // msg notify
        m_pFastNotify = 0;
        m_pSlowNotify = 0;
        m_pNetNotify = 0;

        // for jsp
        m_pProperty = 0;

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    int connection::init()
    {
        int ret = 0;

        if( 0 == ret )
        {
            xos_box::i_callback * pThread = mgr::container()->box()->engine()->fast_threads()->get_thread_in_order();
            {
                m_pFastNotify = mgr::get()->get_callback()->clone();
                m_pFastNotify->set_msg_type( MSG_TYPE_FAST );
                m_pFastNotify->set_thread( pThread );
            }
            {
                m_pNetNotify = mgr::get()->get_callback()->clone();
                m_pNetNotify->set_thread( pThread );
            }
        }

        if( 0 == ret )
        {
            xos_box::i_callback * pThread = mgr::container()->box()->engine()->slow_threads()->get_thread_in_order();
            {
                m_pSlowNotify = fast_notify()->clone();
                m_pSlowNotify->set_msg_type( MSG_TYPE_SLOW );
                m_pSlowNotify->set_thread( pThread );
            }
        }

        if( 0 == ret )
        {
            m_pSendNetEncodeDataList = mgr::container()->box()->list();
            m_pRecvNetEncodeDataList = mgr::container()->box()->list();
            m_pRecvDataList = mgr::container()->box()->list();
            m_pProperty = mgr::container()->box()->get_str_prop();
        }

        return ret;
    }

    int connection::term()
    {
        int ret = 0;
        xos_stl::release_interface( m_pSendNetEncodeDataList );
        xos_stl::release_interface( m_pRecvNetEncodeDataList );
        xos_stl::release_interface( m_pRecvDataList );
        xos_stl::release_interface( m_pProperty );
        xos_stl::release_interface( m_pFastNotify );
        xos_stl::release_interface( m_pSlowNotify );
        xos_stl::release_interface( m_pNetNotify );
        xos_stl::release_interface( m_pSsl );
        xos_stl::term_pool_item( m_pRecvTask );
        xos_stl::term_pool_item( m_pProcTask );
        m_task_list.put_back_to_pool();
        init_data();
        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

} // xos_http
